/**
 *  \file can_int_tx.c
 *
 *  \brief Internal can transmit function
 *
 *  \author dajin.li  <dajin.li@linde-china.com>
 *
 *
 */

/*===============================================[ private includes  ]================================================*/
#include "can_int_tx.h"
#include "../pal/pal_mem.h"
#include "../sched/sched.h"
#include "../canmsg/canmsg.h"
#include "../nth/nth.h"
#include "../can/can.h"
#include "../endian/endian_write.h"
#include "../endian/endian.h"
#include "../canid/canid.h"
#include "../cancom/cancom.h"
#include "../saturated/saturated.h"
#include "can_int_rx.h"
#include "../app/app.h"
#include "../mcu/mcu.h"
#include "../crc16/crc16.h"
#include "../u2c/u2c_dataexchange.h"


/*===============================================[ private defines   ]================================================*/
/*V_INT_TX_PDO1 0x191*/
#define v_int_pdo1_data                                         can_int_tx.signal.v_int_tx_pdo1.u8data
#define v_int_pdo1_steer_angle_can                              can_int_tx.signal.v_int_tx_pdo1.store.v_steer_angle
#define v_int_pdo1_park_break_in_d_can                          can_int_tx.signal.v_int_tx_pdo1.store.v_park_break_in_d
#define v_int_pdo1_neutral_position_in_d_can                    can_int_tx.signal.v_int_tx_pdo1.store.v_neutral_position_in_d
#define v_int_pdo1_reverse_in_d_can                             can_int_tx.signal.v_int_tx_pdo1.store.v_reverse_in_d
#define v_int_pdo1_forward_in_d_can                             can_int_tx.signal.v_int_tx_pdo1.store.v_forward_in_d
#define v_int_pdo1_option_pedal_can                             can_int_tx.signal.v_int_tx_pdo1.store.v_option_pedal
#define v_int_pdo1_option_steer_angle_sensor_can                can_int_tx.signal.v_int_tx_pdo1.store.v_option_steerAngleSensor
#define v_int_pdo1_inv2_enable_can                              can_int_tx.signal.v_int_tx_pdo1.store.v_inv2_enable
#define v_int_pdo1_inv1_enable_can                              can_int_tx.signal.v_int_tx_pdo1.store.v_inv1_enable
#define v_int_pdo1_seat_swtich_in_d_can                         can_int_tx.signal.v_int_tx_pdo1.store.v_seat_swtich_in_d
#define v_int_pdo1_seat_switch_nc_in_d_can                      can_int_tx.signal.v_int_tx_pdo1.store.v_seat_switch_nc_in_d
#define v_int_pdo1_msg_cnt_can                                  can_int_tx.signal.v_int_tx_pdo1.store.v_int_pdo1_msg_cnt
#define v_int_pdo1_msg_checksum_can                             can_int_tx.signal.v_int_tx_pdo1.store.v_int_pdo1_msg_checksum

/*V_INT_TX_PDO2 0x291*/
#define v_int_pdo2_data                                         can_int_tx.signal.v_int_tx_pdo2.u8data
#define v_int_pdo2_accelerator_can                              can_int_tx.signal.v_int_tx_pdo2.store.v_accelerator
#define v_int_pdo2_dc_link_in_a_can                             can_int_tx.signal.v_int_tx_pdo2.store.v_dc_link_in_a
#define v_int_pdo2_msg_cnt_can                                  can_int_tx.signal.v_int_tx_pdo2.store.v_int_pdo2_msg_cnt
#define v_int_pdo2_msg_checksum_can                             can_int_tx.signal.v_int_tx_pdo2.store.v_int_pdo2_msg_checksum

/*V_INT_TX_PDO3 0x391*/
#define v_int_pdo3_data                                         can_int_tx.signal.v_int_tx_pdo3.u8data
#define v_int_pdo3_traction_motor_speed_can                     can_int_tx.signal.v_int_tx_pdo3.store.v_traction_motor_speed
#define v_int_pdo3_5v_current_sensor_in_a_can                   can_int_tx.signal.v_int_tx_pdo3.store.v_5v_current_sensor_in_a
#define v_int_pdo3_msg_cnt_can                                  can_int_tx.signal.v_int_tx_pdo3.store.v_int_pdo3_msg_cnt
#define v_int_pdo3_msg_checksum_can                             can_int_tx.signal.v_int_tx_pdo3.store.v_int_pdo3_msg_checksum

/*V_INT_TX_PDO4 0x491*/
#define v_int_pdo4_data                                         can_int_tx.signal.v_int_tx_pdo4.u8data
#define v_int_pdo4_137v_supply_in_a_can                         can_int_tx.signal.v_int_tx_pdo4.store.v_137v_supply_in_a
#define v_int_pdo4_key_swtich_in_a_can                          can_int_tx.signal.v_int_tx_pdo4.store.v_key_swtich_in_a
#define v_int_pdo4_msg_cnt_can                                  can_int_tx.signal.v_int_tx_pdo4.store.v_int_pdo4_msg_cnt
#define v_int_pdo4_msg_checksum_can                             can_int_tx.signal.v_int_tx_pdo4.store.v_int_pdo4_msg_checksum


/*===============================================[ private datatypes ]================================================*/

struct can_int_tx_signal
{
    union
    {
        U8  u8data[8];
        struct
        {
            S16 v_steer_angle;                         /*Byte0&1   0  :15  0.1 degree*/
            U8  v_reserve0;                            /*Byte2     16 :23*/
            U8  v_reserve1;                            /*Byte3     24 :31*/
            U8  v_park_break_in_d:1;                   /*Byte4     32 :32*/
            U8  v_neutral_position_in_d:1;             /*Byte4     33 :33*/
            U8  v_reverse_in_d:1;                      /*Byte4     34 :34*/
            U8  v_forward_in_d:1;                      /*Byte4     35 :35*/
            U8  v_option_pedal:2;                      /*Byte4     36 :37*/
            U8  v_option_steerAngleSensor:2;           /*Byte4     38 :39*/
            U8  v_int_pdo1_msg_cnt:4;                  /*Byte5     40 :43*/
            U8  v_inv2_enable:1;                       /*Byte4     44 :44*/
            U8  v_inv1_enable:1;                       /*Byte4     45 :45*/
            U8  v_seat_swtich_in_d:1;                  /*Byte4     46 :46*/
            U8  v_seat_switch_nc_in_d:1;               /*Byte4     47 :47*/
            U16 v_int_pdo1_msg_checksum;               /*Byte6&7   48 :63*/
        }store;
    }v_int_tx_pdo1;


    union
    {
        U8  u8data[8];
        struct
        {
            S16 v_accelerator;                         /*Byte0&1   0  :15 0.1 %*/
            S16 v_dc_link_in_a;                        /*Byte2&3   16 :31 0.01 V*/
            U8  reserve0;                              /*Byte4     32 :39*/
            U8  v_int_pdo2_msg_cnt:4;                  /*Byte5     40 :43*/
            U8  reserve1:4;                            /*Byte5     44 :47*/
            U16 v_int_pdo2_msg_checksum;               /*Byte6&7   48 :63*/
        }store;
    }v_int_tx_pdo2;


    union
    {
        U8  u8data[8];
        struct
        {
            S16 v_traction_motor_speed;                /*Byte0&1   0  :15 rpm*/ 
            S16 v_5v_current_sensor_in_a;              /*Byte2&3   16 :31 mv*/
            U8  reserve1;                              /*Byte4     32 :39*/
            U8  v_int_pdo3_msg_cnt:4;                  /*Byte5     40 :43*/
            U8  reserve2:4;                            /*Byte5     44 :47*/
            U16 v_int_pdo3_msg_checksum;               /*Byte6&7   48 :63*/
        }store;
    }v_int_tx_pdo3;

    union
    {
        U8  u8data[8];
        struct
        {
            S16 v_137v_supply_in_a;                    /*Byte0&1   0  :15 v, 0.01*/
            S16 v_key_swtich_in_a;                     /*Byte2&3   16 :31 v, 0.01*/
            U8  reserve1;                              /*Byte4     32 :39*/
            U8  v_int_pdo4_msg_cnt:4;                  /*Byte5     40 :43*/
            U8  reserve2:4;                            /*Byte5     44 :47*/
            U16 v_int_pdo4_msg_checksum;               /*Byte6&7   48 :63*/
        }store;
    }v_int_tx_pdo4;
};


/** Private variables */

struct can_int_tx_private
{
   U8 send_timer1ms;
   struct tasklet task_1ms;
   struct tasklet task_10ms;
   struct can_int_tx_signal signal;

};

/*===============================================[ private variables ]================================================*/
static struct can_int_tx_private can_int_tx;


/*===============================================[ private functions ]================================================*/
static void can_int_tx_1ms_service (struct tasklet *task);
static void can_int_tx_10ms_service (struct tasklet *task);
static void can_int_tx_send_msg(void);
static void PrTrmIntTxPDO1(void);
static void PrTrmIntTxPDO2(void);
static void PrTrmIntTxPDO3(void);
static void PrTrmIntTxPDO4(void);

/*================================================[ inline functions ]================================================*/

/*================================================[ public functions ]================================================*/
RC can_int_tx_initialize( void )
{
   pal_memzero( &can_int_tx, sizeof can_int_tx);
   tasklet_assign( sched_get_slice_1ms(),  &can_int_tx.task_1ms,   can_int_tx_1ms_service, NIL );
   tasklet_assign( sched_get_slice_10ms(), &can_int_tx.task_10ms,  can_int_tx_10ms_service, NIL );
   return RC_SUCCESS;
}



/*===============================================[ private functions ]================================================*/

static void can_int_tx_1ms_service (struct tasklet *task)
{
   UNREFERENCED( task );
   can_int_tx_send_msg();
}

static void can_int_tx_10ms_service (struct tasklet *task)
{
   UNREFERENCED( task );
}



/* this function should be called every 10 ms */
static void can_int_tx_send_msg(void)
{
    if(NTH(&can_int_tx.send_timer1ms,9))
    {
        PrTrmIntTxPDO1();
        can_tx( can_channel_int, V_INT_TX_PDO1,  can_int_tx.signal.v_int_tx_pdo1.u8data,8);// can_int_tx_send_pdo1();
    }

    if((can_int_tx.send_timer1ms % 10) == 1)
    {
        PrTrmIntTxPDO2();
        can_tx( can_channel_int, V_INT_TX_PDO2,  can_int_tx.signal.v_int_tx_pdo2.u8data,8);// can_int_tx_send_pdo2();
    }
    if((can_int_tx.send_timer1ms % 10) == 2)
    {
        PrTrmIntTxPDO3();
        can_tx( can_channel_int, V_INT_TX_PDO3,  can_int_tx.signal.v_int_tx_pdo3.u8data,8);// can_int_tx_send_pdo3();
    }

    if((can_int_tx.send_timer1ms % 10) == 3)
    {
        PrTrmIntTxPDO4();
        can_tx( can_channel_int, V_INT_TX_PDO4,  can_int_tx.signal.v_int_tx_pdo4.u8data,8);// can_int_tx_send_pdo4();
    }
}

static void PrTrmIntTxPDO1(void)
{
    static U8 msgCnt = 0;
    U16 can_id = V_INT_TX_PDO1;
    v_int_pdo1_steer_angle_can               = u2c_data_output.vehicle_steer_angle_v;
    v_int_pdo1_park_break_in_d_can           = u2c_data_output.vehicle_park_brake_in_v ;
    v_int_pdo1_neutral_position_in_d_can     = u2c_data_output.vehicle_neutral_position_v;
    v_int_pdo1_reverse_in_d_can              = u2c_data_output.vehicle_reverse_in_v;
    v_int_pdo1_forward_in_d_can              = u2c_data_output.vehicle_forward_in_v;
    v_int_pdo1_option_pedal_can              = u2c_data_output.vehicle_option_pedal_v;
    v_int_pdo1_option_steer_angle_sensor_can = u2c_data_output.vehicle_option_steerAngleSensor_v;
    v_int_pdo1_inv1_enable_can               = u2c_data_output.vehicle_inv1_enable_v;
    v_int_pdo1_inv2_enable_can               = u2c_data_output.vehicle_inv2_enable_v;
    v_int_pdo1_seat_swtich_in_d_can          = u2c_data_output.vehicle_seat_switch_in_v;
    v_int_pdo1_seat_switch_nc_in_d_can       = u2c_data_output.vehicle_seat_switch_nc_in_v;
    v_int_pdo1_msg_cnt_can                   = (msgCnt++)&0x0f;
    v_int_pdo1_msg_checksum_can              = crc16(0xffff, &can_id, 2);
    v_int_pdo1_msg_checksum_can              = crc16(v_int_pdo1_msg_checksum_can, v_int_pdo1_data, 0x06);

}
static void PrTrmIntTxPDO2(void)
{
    static U8 msgCnt = 0;
    U16 can_id = V_INT_TX_PDO2;
    v_int_pdo2_accelerator_can            = u2c_data_output.vehicle_accelerator_v;
    v_int_pdo2_dc_link_in_a_can           = u2c_data_output.vehicle_dc_link_in_v / can_resol_voltage_drive;
    v_int_pdo2_msg_cnt_can                = (msgCnt++)&0x0f;
    v_int_pdo2_msg_checksum_can           = crc16(0xffff, &can_id, 2);
    v_int_pdo2_msg_checksum_can           = crc16(v_int_pdo2_msg_checksum_can, v_int_pdo2_data, 0x06);

}
static void PrTrmIntTxPDO3(void)
{
    static U8 msgCnt = 0;
    U16 can_id = V_INT_TX_PDO3;
    v_int_pdo3_traction_motor_speed_can     = u2c_data_output.vehicle_traction_motor_speed_v;
    v_int_pdo3_5v_current_sensor_in_a_can   = u2c_data_output.vehicle_current_sensors_vol_v / can_resol_voltage_sensor;
    v_int_pdo3_msg_cnt_can                  = (msgCnt++)&0x0f;
    v_int_pdo3_msg_checksum_can             = crc16(0xffff, &can_id, 2);
    v_int_pdo3_msg_checksum_can             = crc16(v_int_pdo3_msg_checksum_can, v_int_pdo3_data, 0x06);

}
static void PrTrmIntTxPDO4(void)
{
    static U8 msgCnt = 0;
    
    U16 can_id = V_INT_TX_PDO4;
    v_int_pdo4_137v_supply_in_a_can        = u2c_data_output.vehicle_power_supply_v / can_resol_voltage_drive;
    v_int_pdo4_key_swtich_in_a_can         = u2c_data_output.vehicle_key_switch_in_v / can_resol_voltage_drive;
    v_int_pdo4_msg_cnt_can                 = (msgCnt++)&0x0f;
    v_int_pdo4_msg_checksum_can            = crc16(0xffff, &can_id, 2);
    v_int_pdo4_msg_checksum_can            = crc16(v_int_pdo4_msg_checksum_can, v_int_pdo4_data, 0x06);

}

/***********************************************************************************************************************
 *                             Copyright 2018 Linde Material Handling. All rights reserved.                             *
 ***********************************************************************************************************************/
